package org.dwpd.service.blog.impl;

import cn.hutool.core.util.BooleanUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dwpd.domain.common.Result;
import org.dwpd.mapper.blog.BlogMapper;
import org.dwpd.mapper.user.UserMapper;
import org.dwpd.domain.blog.Blog;
import org.dwpd.domain.blog.BlogComment;
import org.dwpd.domain.blog.BlogCommentDTO;
import org.dwpd.domain.blog.BlogInfo;
import org.dwpd.service.blog.BlogService;
import org.dwpd.service.file.FileService;
import org.dwpd.utils.RedisConstants;
import org.dwpd.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.sql.Date;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Package:org.dwpd.service.impl
 *
 * @ClassName:BlogServiceImpl
 * @Create:2024/8/18 16:21
 **/
@Service
@Slf4j
public class BlogServiceImpl implements BlogService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private BlogMapper blogMapper;
    @Resource
    private UserMapper userMapper;

    @Resource
    private FileService fileService;

    @Resource
    private ObjectMapper objectMapper;

    /**
     * 上传图片
     * @param multipartFiles
     * @return
     */
    @Override
    public Result uploadImages(List<MultipartFile> multipartFiles) throws IOException {
        ArrayList<String> arrayList = new ArrayList<>();
        //图片批量上传至云服务器并返回返回地址，放入数组
        for (int i = 0; i < multipartFiles.size();i++){
            String fileName = fileService.upload(multipartFiles.get(i));
            arrayList.add(fileName);
        }
        log.info("图片数组:{}",arrayList);
        //返回结果集
        return Result.success(arrayList);
    }

    @Override
    @Transactional
    public Result saveBlog(Blog blog) {
        //获取用户ID
        Integer userId = UserHolder.getUser().getUserId();
        blog.setUserId(userId);
        //保存博客
        Integer i = blogMapper.saveBlog(blog);
        if (i>0){
            return Result.success("");
        }
        return Result.fail(-1,"保存失败");

    }

    /**
     * 查询博客详情
     * @param id
     * @return
     */
    @Override
    public Result getBlogDetail(Integer id) throws JsonProcessingException {
        BlogInfo blogInfo = new BlogInfo();
        //查询reids缓存
        String key = RedisConstants.BLOG_DETAIL_KEY + id;
        String ishadBlog = stringRedisTemplate.opsForValue().get(key);
        //判断是否存在
        if (ishadBlog!=null){
            //存在,转换为blogInfo对象
            blogInfo =  objectMapper.readValue(ishadBlog, BlogInfo.class);
            log.info("帖子详情blog:{}",blogInfo);
            //刷新redis中数据有效期
            stringRedisTemplate.expire(key,RedisConstants.BLOG_DETAIL_TTL, TimeUnit.HOURS);
            return Result.success(blogInfo);
        }
        //不存在则数据库查询博客
        blogInfo = blogMapper.selectBlogInfo(id);
        log.info("获取博客详情:{}",blogInfo);
        if (blogInfo == null){
            return Result.fail(-1,"博客不存在");
        }
        //缓存博客
        stringRedisTemplate.opsForValue().set(key,objectMapper.writeValueAsString(blogInfo),RedisConstants.BLOG_DETAIL_TTL,TimeUnit.HOURS);
        //返回
        return Result.success(blogInfo);
    }

    /**
     * 评论
     * @param comment
     * @return
     * @throws JsonProcessingException
     */
    @Override
    @Transactional
    public Result comment(BlogComment comment) throws JsonProcessingException {
        //获取当前用户ID
        Integer userId = UserHolder.getUser().getUserId();
        //获取博主ID
        Integer rootComment = blogMapper.selectBlogHostId(comment.getBlogId());
        comment.setUserId(userId);
        comment.setRootCommentId(rootComment);
        //将评论信息存入数据库中
        comment.setCreateTime(Date.valueOf(LocalDate.now()));
        Integer id = blogMapper.comment(comment);
        //判断插入数据是否成功
        if (id==0){
            return Result.fail(-1,"评论失败");
        }
        return Result.success("评论成功");
    }

    /**
     * 获取博客的所有评论
     * @param id
     * @return
     * @throws IOException
     */
    @Override
    public Result getComments(Integer id) throws IOException {
        List<BlogCommentDTO> result = blogMapper.selectBlogCommentPage(id);
        return Result.success(result);

    }

    /**
     * 删除博客
     * @param id
     * @return
     */
    @Transactional
    @Override
    public Result deleteBlog(Integer id) {
        String blogKey = RedisConstants.BLOG_DETAIL_KEY+id;
        String blogCommentKey = RedisConstants.BLOG_COMMENT_KEY+id;
        //查询数据库
        BlogInfo blogInfo = blogMapper.selectBlogInfo(id);
        if (blogInfo==null){
            return Result.fail(-1,"该博客已不存在");
        }
        //判断自己是不是博主本人
        if (blogInfo.getUserId() != UserHolder.getUser().getUserId()){
            return Result.fail(-1,"当前博客不是您的作品");
        }
        //删除博客
        Integer row = blogMapper.deleteBlogById(id);
        if (row == 0){
            return Result.fail(-1,"删除失败");
        }
        //删除博客评论
        row = blogMapper.deleteCommentByBlogId(id);
        //删除缓存
        stringRedisTemplate.delete(blogKey);
        stringRedisTemplate.delete(blogCommentKey);
        return Result.success("");
    }

    /**
     * 删除某一条评论
     * @param id
     * @return
     */
    @Override
    @Transactional
    public Result deleteBlogComment(Integer id) {
        //获取当前用户id
        Integer userId = UserHolder.getUser().getUserId();
        //在数据库中查找该评论
        BlogComment blogComment = blogMapper.selectBlogCommentById(id);
        if (blogComment == null){
            return Result.fail(-1,"该评论已不存在");
        }

        //判断自己是否为该评论的发评者或者博主
        if (userId.equals(blogComment.getUserId()) || userId.equals(blogComment.getRootCommentId())){
            //是则删除评论，并删除评论缓存
            Integer row = blogMapper.deleteBlogCommentById(id);
            if (row > 0){
                return Result.success("删评成功");
            }
            return Result.fail(-1,"删评失败");
        }
        return Result.fail(-1,"你无权删除此评论");
    }

    /**
     * 博客点赞
     * @param id
     * @return
     */
    @Override
    @Transactional
    public Result blogLiked(Integer id) {
        //获取登录用户
        Integer userId = UserHolder.getUser().getUserId();
        String likedKey = RedisConstants.BLOG_LIKED_KEY+id;
        String dislikedKey = RedisConstants.BLOG_DISLIKED_KEY+id;
        String blogKey = RedisConstants.BLOG_DETAIL_KEY + id;
        //判断当前登录用户是否已被点赞
        Boolean isAddMember = stringRedisTemplate.opsForSet().isMember(likedKey, userId.toString());
        //判断
        if (BooleanUtil.isTrue(isAddMember)){
            //如果已经点赞则取消点赞
            //数据库liked-1
            Integer addRow = blogMapper.subLiked(id);
            stringRedisTemplate.opsForSet().remove(likedKey,userId.toString());
            stringRedisTemplate.expire(likedKey,RedisConstants.BLOG_LIKED_TTL,TimeUnit.DAYS);
            //移除原博客缓存
            stringRedisTemplate.delete(blogKey);
            return Result.success("取消点赞");
        }
        //如果未点赞，数据库liked+1，并判断是否点踩
        Integer addRow = blogMapper.addLiked(id);
        if (addRow > 0){
            //添加点赞缓存
            stringRedisTemplate.opsForSet().add(likedKey,userId.toString());
            stringRedisTemplate.expire(likedKey,RedisConstants.BLOG_LIKED_TTL,TimeUnit.DAYS);
            Boolean isSubMember = stringRedisTemplate.opsForSet().isMember(dislikedKey, userId.toString());
            //如果点过踩，则数据库disliked-1
            if (BooleanUtil.isTrue(isSubMember)) {
                Integer subRow = blogMapper.subDisliked(id);
                if (subRow > 0){
                    //移除点踩缓存
                    stringRedisTemplate.opsForSet().remove(dislikedKey,userId.toString());
                    stringRedisTemplate.expire(dislikedKey,RedisConstants.BLOG_DISLIKED_TTL,TimeUnit.DAYS);
                    //移除原博客缓存
                    stringRedisTemplate.delete(blogKey);
                }
            }
            return Result.success("点赞成功");
        }
        return Result.fail(-1,"点赞失败");
    }

    /**
     * 博客点踩
     * @param id
     * @return
     */

    @Override
    public Result blogDisliked(Integer id) {
        //获取登录用户
        Integer userId = UserHolder.getUser().getUserId();
        String likedKey = RedisConstants.BLOG_LIKED_KEY+id;
        String dislikedKey = RedisConstants.BLOG_DISLIKED_KEY+id;
        String blogKey = RedisConstants.BLOG_DETAIL_KEY + id;
        //判断当前登录用户是否已点踩
        Boolean isAddMember = stringRedisTemplate.opsForSet().isMember(dislikedKey, userId.toString());
        //判断
        if (BooleanUtil.isTrue(isAddMember)){
            //如果已经点踩则取消点踩
            //数据库disliked-1
            Integer addRow = blogMapper.subDisliked(id);
            stringRedisTemplate.opsForSet().remove(dislikedKey,userId.toString());
            stringRedisTemplate.expire(dislikedKey,RedisConstants.BLOG_DISLIKED_TTL,TimeUnit.DAYS);
            //移除原博客缓存
            stringRedisTemplate.delete(blogKey);
            return Result.success("取消点踩");
        }
        Integer addRow = blogMapper.addDisliked(id);
        if (addRow > 0){
            //添加点踩缓存
            stringRedisTemplate.opsForSet().add(dislikedKey,userId.toString());
            stringRedisTemplate.expire(likedKey,RedisConstants.BLOG_DISLIKED_TTL,TimeUnit.DAYS);
            //判断是否点过赞
            Boolean isSubMember = stringRedisTemplate.opsForSet().isMember(likedKey,userId.toString());
            //如果点过赞，则数据库liked-1
            if (BooleanUtil.isTrue(isSubMember)){
                Integer subRow = blogMapper.subLiked(id);
                if (subRow > 0){
                    //移除点赞缓存
                    stringRedisTemplate.opsForSet().remove(likedKey,userId.toString());
                    //刷新点赞缓存时间
                    stringRedisTemplate.expire(likedKey,RedisConstants.BLOG_LIKED_TTL,TimeUnit.DAYS);
                    //移除原博客缓存
                    stringRedisTemplate.delete(blogKey);
                }
            }
            return Result.success("点踩成功");
        }
        return Result.fail(-1,"点踩失败");
    }

    /**
     * 每次查询6条博客
     * @param pageNum
     * @return
     */
    @Override
    public Result getBlogList(Integer pageNum) {
        Integer index = (pageNum-1)*6;
        //在数据库中获取数据
        List<BlogInfo> list = blogMapper.selectBlogList(index);
        log.info("list:{}",list);
        return Result.success(list);
    }

    /**
     * 获取指定用户的博客列表
     * @param userId 用户Id
     * @return
     */
    @Override
    public Result getBlogListFromUserId(Integer userId) {
        List<BlogInfo> list = blogMapper.selectBlogListByUserId(userId);
        return Result.success(list);
    }
}